﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using Microsoft.Security.Application;
using System.Security.Cryptography;
using System.IO;
using System.Net.Mail;
using System.Net;
using System.Reflection;

namespace YiDa.Infrastructure
{
    public class Utils
    {
        #region Encode

        /// <summary>
        /// 生成html的编码
        /// </summary>
        /// <param name="src"></param>
        /// <returns></returns>
        /// <remarks>意图参见: http://www.troyhunt.com/2010/05/owasp-top-10-for-net-developers-part-2.html </remarks>
        public static string HtmlEncode(string src)
        {
            return Microsoft.Security.Application.Encoder.HtmlEncode(src);
        }

        /// <summary>
        /// 利用AntiXssLibrary库实现对JavaScript脚本的编码
        /// </summary>
        /// <param name="src"></param>
        /// <returns></returns>
        /// <remarks>意图参见: http://www.troyhunt.com/2010/05/owasp-top-10-for-net-developers-part-2.html </remarks>
        public static string JavaScriptEncode(string src)
        {
            return Microsoft.Security.Application.Encoder.JavaScriptEncode(src);            
        }

        #endregion

        #region MD5

        /// <summary>
        /// 获取Md5码
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        /// <remarks>作为加密时不建议直接使用，原因是: http://www.troyhunt.com/2011/06/owasp-top-10-for-net-developers-part-7.html </remarks>
        public static string GetMd5Hash(string input)
        {
            var hasher = MD5.Create();
            var data = hasher.ComputeHash(Encoding.Default.GetBytes(input));
            var builder = new StringBuilder();

            for (var i = 0; i < data.Length; i++)
            {
                builder.Append(data[i].ToString("x2"));
            }

            return builder.ToString();
        }

        /// <summary>
        /// 获取随机字符串
        /// </summary>
        /// <param name="size"></param>
        /// <example>var s=CreateSalt(8);</example>
        /// <returns></returns>
        /// <remarks>意图参见: http://www.troyhunt.com/2011/06/owasp-top-10-for-net-developers-part-7.html </remarks>
        public static string CreateSalt(int size)
        {
            var rng = new RNGCryptoServiceProvider();
            var buff = new byte[size];
            rng.GetBytes(buff);
            return Convert.ToBase64String(buff);
        }

        /// <summary>
        /// 通过指定一个随机串与输入值进行组合来形成MD5值
        /// 如果用来加密密码的话，在数据库中要将salt值一同保存,在验证时，通过计算用户输入的密码+salt来判断得到的MD5
        /// 值是否与数据库中的一致
        /// </summary>
        /// <param name="input"></param>
        /// <param name="salt"></param>
        /// <returns></returns>
        /// <example>var salt=CreateSalt(8);var md5=GetMd5Hash("123456",salt);</example>
        /// <remarks>意图参见: http://www.troyhunt.com/2011/06/owasp-top-10-for-net-developers-part-7.html </remarks>
        public static string GetMd5Hash(string input, string salt)
        {
            var hasher = MD5.Create();
            var data = hasher.ComputeHash(Encoding.Default.GetBytes(input + salt));
            var builder = new StringBuilder();

            for (var i = 0; i < data.Length; i++)
            {
                builder.Append(data[i].ToString("x2"));
            }

            return builder.ToString();
        }

        #endregion

        #region AESEncrypt

        /// <summary>
        /// 生成Key和IV（初始向量）
        /// 在系统外有两种使用方式：
        /// 1、保存好password以及salt值，每次需要加解密时，可以通过password以及salt生成Key和IV,再进行加解密。
        /// 2、只调用一次GetKeyAndIVFromPasswordAndSalt，然后将Key在系统外进行保存。在加密时，将IV与密文一同存储。在解密时，用Key将密文和IV调用Decrypt方法进行解密
        /// </summary>
        /// <param name="password"></param>
        /// <param name="salt"></param>
        /// <param name="symmetricAlgorithm"></param>
        /// <param name="key"></param>
        /// <param name="iv"></param>
        /// <remarks>意图参见: http://www.troyhunt.com/2011/06/owasp-top-10-for-net-developers-part-7.html </remarks>
        public static void GetKeyAndIVFromPasswordAndSalt(string password, byte[] salt,SymmetricAlgorithm symmetricAlgorithm, ref byte[] key, ref byte[] iv)
        {
            var rfc2898DeriveBytes = new Rfc2898DeriveBytes(password, salt);
            key = rfc2898DeriveBytes.GetBytes(symmetricAlgorithm.KeySize / 8);
            iv = rfc2898DeriveBytes.GetBytes(symmetricAlgorithm.BlockSize / 8);
        }

        public static byte[] Encrypt(string clearText, byte[] key, byte[] iv)
        {
            var clearTextBytes = Encoding.Default.GetBytes(clearText);
            var rijndael = new RijndaelManaged();
            var transform = rijndael.CreateEncryptor(key, iv);
            var outputStream = new MemoryStream();
            var inputStream = new CryptoStream(outputStream, transform,CryptoStreamMode.Write);
            inputStream.Write(clearTextBytes, 0, clearText.Length);
            inputStream.FlushFinalBlock();
            return outputStream.ToArray();
        }

        public static string Decrypt(byte[] cipherText, byte[] key, byte[] iv)
        {
            var rijndael = new RijndaelManaged();
            var transform = rijndael.CreateDecryptor(key, iv);
            var outputStream = new MemoryStream();
            var inputStream = new CryptoStream(outputStream, transform,CryptoStreamMode.Write);
            inputStream.Write(cipherText, 0, cipherText.Length);
            inputStream.FlushFinalBlock();
            var outputBytes = outputStream.ToArray();
            return Encoding.Default.GetString(outputBytes);
        }

        #endregion

        #region Logger

        private static readonly log4net.ILog log = log4net.LogManager.GetLogger("Application.Logger");                
        
        public static void Log(string message)
        {            
            log.Info(message);
        }

        public static void Log(Exception ex)
        {
            log.Error("异常信息", ex);
        }        

        #endregion

        /// <summary>
        /// 向指定的邮件地址发送邮件。
        /// </summary>
        /// <param name="to">需要发送邮件的邮件地址。</param>
        /// <param name="subject">邮件主题。</param>
        /// <param name="content">邮件内容。</param>
        public static void SendEmail(string to, string subject, string content)
        {
            //MailMessage msg = new MailMessage(ByteartRetailConfigurationReader.Instance.EmailSender,
            //    to,
            //    subject,
            //    content);
            //SmtpClient smtpClient = new SmtpClient(ByteartRetailConfigurationReader.Instance.EmailHost);
            //smtpClient.Port = ByteartRetailConfigurationReader.Instance.EmailPort;
            //smtpClient.Credentials = new NetworkCredential(ByteartRetailConfigurationReader.Instance.EmailUserName, ByteartRetailConfigurationReader.Instance.EmailPassword);
            //smtpClient.EnableSsl = ByteartRetailConfigurationReader.Instance.EmailEnableSsl;
            //smtpClient.Send(msg);
        }

        #region Reflection

        public static void setField(Type type, string fieldName, object o, object value)
        {
            FieldInfo fi = type.GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic);
            fi.SetValue(o, value);
        }

        public static void setField(string fieldName, object o, object value)
        {
            setField(o.GetType(), fieldName, o, value);
        }

        public static T getField<T>(Type type, string fieldName, object o)
        {
            T result = default(T);

            FieldInfo fi = type.GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic);
            result = (T)fi.GetValue(o);

            return result;
        }

        public static T getField<T>(string fieldName, object o)
        {
            return getField<T>(o.GetType(), fieldName, o);
        }
        /// <summary>
        /// 获取反射的属性
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="property"></param>
        /// <param name="o"></param>
        /// <returns></returns>
        public static T getPerperty<T>(string property, object o)
        {
            T result;

            Type t = o.GetType();

            PropertyInfo pi = t.GetProperty(property, BindingFlags.GetProperty | BindingFlags.Instance | BindingFlags.NonPublic);
            result = (T)pi.GetValue(o, null);

            return result;
        }

        public static T getPerperty<T>(string property, Type type)
        {
            T result;            

            PropertyInfo pi = type.GetProperty(property, BindingFlags.GetProperty | BindingFlags.Static | BindingFlags.NonPublic);
            result = (T)pi.GetValue(null, null);

            return result;
        }

        public static void setPerperty(string property, object o, object value, object[] index)
        {

            Type t = o.GetType();

            PropertyInfo pi = t.GetProperty(property, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.SetProperty);
            pi.SetValue(o, value, index);

        }

        public static object InvokeMethod(object target, string methodName, object[] parameters)
        {
            return InvokeMethod(target.GetType(), target, methodName, parameters);
        }

        /// <summary>
        /// 反射调用非重载方法
        /// </summary>
        /// <param name="t"></param>
        /// <param name="target"></param>
        /// <param name="methodName"></param>
        /// <param name="parameters"></param>
        /// <returns></returns>
        public static object InvokeMethod(Type t, object target, string methodName, object[] parameters)
        {
            MethodInfo method = null;
            if (target == null)
            {
                method = t.GetMethod(methodName, BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
            }
            else
            {
                method = t.GetMethod(methodName, BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
            }
            var result = method.Invoke(target, parameters);
            return result;
        }

        /// <summary>
        /// 反射调用重载的方法
        /// </summary>
        /// <param name="t"></param>
        /// <param name="target"></param>
        /// <param name="methodName"></param>
        /// <param name="parameters"></param>
        /// <param name="parameterTypes"></param>
        /// <returns></returns>
        public static object InvokeMethod(Type t, object target, string methodName, object[] parameters, Type[] parameterTypes)
        {
            MethodInfo method = null;
            if (target == null)
            {
                method = t.GetMethod(methodName, BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static, Type.DefaultBinder, parameterTypes, null);
            }
            else
            {
                method = t.GetMethod(methodName, BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, Type.DefaultBinder, parameterTypes, null);
            }
            var result = method.Invoke(target, parameters);
            return result;
        }

        #endregion
    }
}
